package com.vichat.gps.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.vichat.business.entity.CommonAlarm;
import com.vichat.business.entity.DistrictFence;
import com.vichat.business.entity.DistrictFenceRule;
import com.vichat.business.entity.DistrictFenceUser;
import com.vichat.business.service.IVcAlarmService;
import com.vichat.business.vo.FenceVO;
import com.vichat.common.cache.RedisHelper;
import com.vichat.common.constant.GlobalConstant;
import com.vichat.common.constant.I18nConstant;
import com.vichat.common.exception.ViChatException;
import com.vichat.common.signal.CmdUtil;
import com.vichat.common.util.DateUtil;
import com.vichat.common.util.I18NUtil;
import com.vichat.common.util.MapTools;
import com.vichat.gps.entity.LocationData;
import com.vichat.user.cache.I18nMappingCache;
import com.vichat.user.entity.SystemMessage;
import com.vichat.user.entity.UserBasic;
import com.vichat.user.service.ISystemMessageService;
import com.vichat.user.service.IUserService;
import com.vichat.user.util.I18nUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.geom.Point2D;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class FenceGpsProcessThread implements Runnable {

    private static Logger logger = LoggerFactory.getLogger(FenceGpsProcessThread.class);


    //围栏 0 出围栏 1 进围栏
    private static ConcurrentHashMap<String, Long> userPolygon = new ConcurrentHashMap<String, Long>();


    IUserService userService;
    List<LocationData> locations;
    IVcAlarmService vcAlarmService;
    ISystemMessageService systemMessageService;
    UserBasic user;
    I18nMappingCache i18nMappingCache;

    public FenceGpsProcessThread(IUserService userService_, IVcAlarmService vcAlarmService_, ISystemMessageService systemMessageService_, GpsAppCache gpsAppCache_, List<LocationData> locations_, I18nMappingCache i18nMappingCache_) {
        this.userService = userService_;
        this.locations = locations_;
        this.vcAlarmService = vcAlarmService_;
        this.systemMessageService = systemMessageService_;
        this.i18nMappingCache = i18nMappingCache_;
    }

    @Override
    public void run() {
        try {
            try {

                for (LocationData location : locations) {
                    checkWithJdkPolygon(location);
                }
            } catch (Exception ee) {
                logger.error(ee.getMessage(), ee);
            }
        } catch (Exception e) {
            logger.error("UploadGpsThread>>>>>>" + e.getMessage(), e);
        }
    }

    /**
     * 判断是否进入告警围栏
     */
    private void checkWithJdkPolygon(LocationData location) throws Exception {
        if (user == null) {
            user = userService.getUserBasicByUid(location.getUid());
        }
        Point2D.Double point = new Point2D.Double(Double.parseDouble(location.getLongitude()), Double.parseDouble(location.getLatitude()));
        Date locTime = new Date(location.getLocTime());
        Map<String, String> fencesMap = RedisHelper.getUserDistrictFences(user.getUid());// 从redis中获取围栏
        //logger.debug(fencesInRedis);
        if (fencesMap != null && fencesMap.size() > 0) {
            for (String fenceIdStr : fencesMap.values()) {
                String fenceStr = RedisHelper.getDistrictFence(user.getPartyId(), Long.valueOf(fenceIdStr));
                if (!StringUtils.isNotBlank(fenceIdStr)) {
                    continue;
                }
                FenceVO fenceVO = JSONObject.parseObject(fenceStr, FenceVO.class);
                DistrictFence fence = fenceVO.getDistrictFence();

                long fenceType = fence.getFenceType();
                //获取围栏范围
                String points = fence.getRegcoords();

                if (StringUtils.isNoneEmpty(points)) {
                    List<Point2D.Double> polygon = getPolygon(points);

                    boolean inPolygon = MapTools.checkWithJdkGeneralPath(point, polygon);//是否在区域内

                    if (!isFenceUser(fenceVO.getDistrictFenceUser())) {//是否电子围栏监控人员
                        continue;
                    }

                    if (!inFenceTime(fenceVO.getDistrictFenceRule(), locTime)) { //是否在电子围栏监控时间范围内
                        continue;
                    }

                    //1 禁入 2 禁出
                    if (fenceType == DistrictFence.FENCE_TYPE_ENTER && inPolygon) {//进入围栏告警
                        if (canCreateFenceAlarm(fenceVO, locTime)) {
//                            String alarmMsg = I18NUtil.getMessage("GpsApiController.uploadGps.msg_sendAlarmIn", new Object[]{"<font color=\"red\">"+ user.getUserName() +"</font>", "<font color=\"red\">["+ fence.getFenceName() +"]</font>"}, GlobalConstant.SYS_LANGUAGE);
                            String alarmMsg = I18nUtils.getMessage(i18nMappingCache, "SYSTEM_ALARM", I18nConstant.info_fenceAlarm_in, new Object[]{user.getUserName(), fence.getFenceName()}, GlobalConstant.SYS_LANGUAGE);
                            logger.error(alarmMsg);
                            //sendAlarmMsg(fence.getFenceId(), user.getUid(), GlobalConstant.IMS_ALARM_IN, alarmMsg, locTime);
                            createFenceAlarm(location, fenceVO, alarmMsg, DistrictFence.FENCE_TYPE_ENTER);
                        }
                    }
                    if (fenceType == DistrictFence.FENCE_TYPE_EXIT && !inPolygon) {//离开围栏告警
                        if (canCreateFenceAlarm(fenceVO, locTime)) {
//                            String alarmMsg = I18NUtil.getMessage("GpsApiController.uploadGps.msg_sendAlarmOut", new Object[]{"<font color=\"red\">"+ user.getUserName() +"</font>", "<font color=\"red\">["+ fence.getFenceName() +"]</font>"}, GlobalConstant.SYS_LANGUAGE);
                            String alarmMsg = I18nUtils.getMessage(i18nMappingCache, "SYSTEM_ALARM", I18nConstant.info_fenceAlarm_out, new Object[]{user.getUserName(), fence.getFenceName()}, GlobalConstant.SYS_LANGUAGE);
                            logger.error(alarmMsg);
                            //sendAlarmMsg(fence.getFenceId(), user.getUid(), GlobalConstant.IMS_ALARM_OUT, alarmMsg, locTime);
                            createFenceAlarm(location, fenceVO, alarmMsg, DistrictFence.FENCE_TYPE_EXIT);
                        }
                    }
                }
            }
        }
    }

    private List<Point2D.Double> getPolygon(String points) {
        try {
            JSONArray pointsJSONArray = JSONArray.parseArray(points);
            List<Point2D.Double> polygon = new ArrayList<>();
            for (Object point : pointsJSONArray) {
                JSONArray xy = (JSONArray) point;
                Point2D.Double addPoint = new Point2D.Double(xy.getDoubleValue(0), xy.getDoubleValue(1));
                polygon.add(addPoint);
            }
            return polygon;
        } catch (Exception e) {
            return null;
        }

    }

    /**
     * 创建围栏告警
     *
     * @param location
     */
    private void createFenceAlarm(LocationData location, FenceVO fenceVO, String alarmContent, long alarmType) {
        CommonAlarm alarm = new CommonAlarm();
        alarm.setUid(user.getUid());
        alarm.setAlarmType(fenceVO.getDistrictFence().getFenceType());
        alarm.setPartyId(user.getPartyId());
        alarm.setOrgId(user.getOrgId());
        alarm.setOrgCode(user.getOrgCode());
        alarm.setAddress(location.getAddress());
        alarm.setLongitude(location.getLongitude());
        alarm.setLatitude(location.getLatitude());
        alarm.setAlarmTime(new Date(location.getLocTime()));
        alarm.setAlarmLevel(fenceVO.getDistrictFenceRule().getAlarmLevel());
        alarm.setObjType(alarmType);
        alarm.setObjId(fenceVO.getDistrictFence().getFenceId());
        vcAlarmService.saveCommonAlarm(alarm);
        RedisHelper.setFenceAlarmTime(user.getUid(), fenceVO.getDistrictFence().getFenceId(), DateUtil.getFormattedDateTime(alarm.getAlarmTime()));

        sendFenceMessage(fenceVO, alarmContent, new Date(), alarmType, alarm);
    }

    private void createSystemMessage(long uid, String content, Date msgTime, long alarmType, CommonAlarm alarm) {
        SystemMessage message = new SystemMessage();
        message.setMsgType(GlobalConstant.SYS_MSG_ALARM);
        message.setUid(uid);
        message.setMsgContent(content);
        message.setMsgTime(msgTime);
        message.setIsRead(0L);
        message.setIsReceive(0L);
        message.setCreateTime(new Date());
        message.setShowType(GlobalConstant.SYS_MSG_SHOW_TYPE_PC);
        message.setMsgLevel(1l);
        message.setObjType(alarmType);
        message.setObjId(alarm.getAlarmId());
        systemMessageService.saveSystemMessage(message);
        CmdUtil.sendImMsg(10000, uid, 0, GlobalConstant.IMS_ALARM_FENCE, JSONObject.toJSONString(message));
    }

    private boolean isFenceUser(List<DistrictFenceUser> districtFenceUsers) {
        boolean result = false;


        for (DistrictFenceUser fenceUser : districtFenceUsers) {
            if (fenceUser.getType() == GlobalConstant.FENCE_USER_TYPE_SENDUSER) {
                continue;
            }

            if (fenceUser.getType() == GlobalConstant.FENCE_USER_TYPE_PARTY) {
                if (fenceUser.getUserId().longValue() == user.getPartyId().longValue()) {
                    result = true;
                    break;
                }
            }
            if (fenceUser.getType() == GlobalConstant.FENCE_USER_TYPE_ORG) {
                if (fenceUser.getUserId().longValue() == user.getOrgId().longValue()) {
                    result = true;
                    break;
                }
            }
            if (fenceUser.getType() == GlobalConstant.FENCE_USER_TYPE_USER) {
                if (fenceUser.getUserId().longValue() == user.getUid().longValue()) {
                    result = true;
                    break;
                }
            }
        }
        if(!result) {
            RedisHelper.delUserDistrictFence(user.getUid(), districtFenceUsers.get(0).getFenceId());
        }

        return result;
    }

    private boolean inFenceTime(DistrictFenceRule fenceRule, Date locTime) {

        boolean isFenceDay = false;//电子围栏当天是否监控

        String ruleStr = fenceRule.getRuleJson();
        JSONObject ruleJSON = JSONObject.parseObject(ruleStr);
        String ruleDate = ruleJSON.getString("ruleDate");
        JSONArray ruleTimes = ruleJSON.getJSONArray("ruleTime");

        //发送日期是否符合规则
        if (fenceRule.getRuleType().longValue() == GlobalConstant.FENCE_DATE_TYPE_WEEK) {
            String weekTime = String.valueOf(DateUtil.getWeek(DateUtil.getTimestatmpByDate(locTime)));
            if (ruleDate.contains(weekTime)) {
                isFenceDay = true;
            }
        } else if (fenceRule.getRuleType().longValue() == GlobalConstant.FENCE_DATE_TYPE_MONTH) {
            String monthTime = String.valueOf(DateUtil.getDay(DateUtil.getTimestatmpByDate(locTime)));
            if (ruleDate.contains(monthTime)) {
                isFenceDay = true;
            }
        } else if (fenceRule.getRuleType().longValue() == GlobalConstant.FENCE_DATE_TYPE_DAY) {
            isFenceDay = true;
        }

        //发送日期是否在发送时间区间内
        if (isFenceDay) {

            for (Object obj : ruleTimes) {
                JSONArray ruleTime = (JSONArray) obj;
                String startTime = ruleTime.getString(0);
                String endTime = ruleTime.getString(1);
                if (DateUtil.isBelong(locTime, startTime, endTime, 1)) {
                    return true;
                }
            }
        }

        return false;
    }

    private boolean canCreateFenceAlarm(FenceVO fenceVO, Date locTime) {
        //是否到下一次发送时间
        String lastAlarmTimeStr = RedisHelper.getFenceAlarmTime(user.uid, fenceVO.getDistrictFenceRule().getFenceId());
        if (StringUtils.isNotBlank(lastAlarmTimeStr)) {
            Date lastAlarmTime = DateUtil.getDateByString(lastAlarmTimeStr);
            if (lastAlarmTime.before(locTime) && DateUtil.getDiffMinutes(lastAlarmTime, locTime) > fenceVO.getDistrictFenceRule().getRuleCondition()) {
                return true;
            }
        } else {
            return true;
        }
        return false;

    }

    private void sendFenceMessage(FenceVO fenceVO, String alarmMsg, Date alramTime, long alarmType, CommonAlarm alarm) {
        List<Long> messageUsers = new ArrayList<>();
        boolean isAlarmOneSelf = false;

        //判断是否发送本人
        DistrictFenceRule districtFenceRule = fenceVO.getDistrictFenceRule();
        String ruleJson = districtFenceRule.getRuleJson();
        if (StringUtils.isNotBlank(ruleJson)) {
            JSONObject ruleJsonObj = JSONObject.parseObject(ruleJson);
            isAlarmOneSelf = ruleJsonObj.getBooleanValue("isAlarmOneSelf");
        }
        if (isAlarmOneSelf) {
            messageUsers.add(user.uid);
        }

        List<DistrictFenceUser> districtFenceUserList = fenceVO.getDistrictFenceUser();
        if (districtFenceUserList != null && !districtFenceUserList.isEmpty()) {
            for (DistrictFenceUser fenceUser : districtFenceUserList) {
                if (fenceUser.getType() == GlobalConstant.FENCE_USER_TYPE_SENDUSER) {
                    messageUsers.add(fenceUser.getUserId());
                }
            }
        }


        for (Long uid : messageUsers) {
            createSystemMessage(uid, alarmMsg, alramTime, alarmType, alarm);
        }
    }

}
